'use strict'

process.chdir(__dirname)

const titbit = require('titbit')
const fs = require('fs')
const dbcfg = require('./dbconfig.js')
const pg = require('pg')
const wxkey = require('./wxkey.js')
const {httpcli} = require('gohttp')
const token = require('titbit-token')

try {
  fs.accessSync('./images')
} catch (err) {
  fs.mkdirSync('./images')
}

let psql = new pg.Pool(dbcfg)

let cert_path = '/usr/local/cert'

const app = new titbit({
  //开启调试模式，若有错误会输出错误信息。
  debug: true,
  globalLog: true,
  cert: `${cert_path}/www.vvh5.com.pem`,
  key: `${cert_path}/www.vvh5.com.key`
})

//添加路由
app.get('/', async c => {
  c.send('ok')
})

/** ------------- content路由 ----------------- */

//获取内容列表
app.get('/content', async c => {
  let ret = await psql.query(`select * from content`)
  //等效于 c.res.body = ret.rows
  c.send(ret.rows)
})

//获取具体内容
app.get('/content/:id', async c => {
  let sqltext = `SELECT * FROM content WHERE id=$1`

  let r = await psql.query(sqltext, [c.param.id])

  if (r.rowCount === 0) {
    return c.status(404).send('content not found')
  }

  c.send(r.rows[0])

})

//创建内容
app.post('/content', async c => {
  try {
    //提交的Body数据通过c.body获取
    let data = JSON.parse(c.body)

    let sqltext = `INSERT INTO `
      + ` content(id, add_time, detail, title, update_time) `
      + ` VALUES ($1, $2, $3, $4, $5)`

    //生成唯一ID
    let id = c.helper.makeId()
    let tm = Date.now()

    let r = await psql.query(sqltext, [
      id, tm, data.detail, data.title, tm
    ])

    if (r.rowCount === 0) {
      return c.status(500).send('failed')
    }

    c.send(id)

  } catch (err) {
    c.status(400).send('it is not json data')
  }
})

app.delete('/content/:id', async c => {
  let r = await psql.query(`DELETE FROM content WHERE id=$1`, [ c.param.id ])

  c.send({
    count: r.rowCount
  })

})

/** ------------- content路由 - END ----------------- */

app.get('/upload', async c => {
  // c.reply是响应对象，可写的流，
  // 在HTTP/1.1中指向response，在HTTP/2中指向http2stream
  await c.helper.pipe('./upload.html', c.reply)
})

app.post('/upload', async c => {
  //根据name获取文件对象。
  let f = c.getFile('image')

  if (!f) {
    return c.status(400).send('image not found')
  }

  //根据传入的原始文件名生成唯一文件名，主要使用f.filename的扩展名。
  let fname = c.helper.makeName(f.filename)

  //移动文件到指定位置。
  await c.moveFile(f, `./images/${fname}`)

  c.send(fname)

})

//返回图片数据
app.get('/image/:name', async c => {
  //c.param是一个对象，其中的key值是路由参数的名称。
  let imgname = c.param.name

  await c.helper.pipe(`./images/${imgname}`, c.reply)

})

let tok = new token({
  //token有效期，单位为秒
  expires: 45,
  //必须是32位字符
  key: '1qaz2wsx3edc4rfv5tgb6yhn7ujmki89',

  //必须是16位字符
  iv: '1q2w3e4r5t6y7u8i'
})

app.get('/mp-login/:code', async c => {
  let auth_url = `https://api.weixin.qq.com/sns/jscode2session`
          + `?appid=${wxkey.appid}`
          + `&secret=${wxkey.secret}`
          + `&js_code=${c.param.code}`
          + `&grant_type=authorization_code`

  let ret = await httpcli.get(auth_url)
                        .then(res => {
                          return res.json()
                        })
  
  c.send( tok.make(ret) )
})

app.get('/decrypt/:token', async c => {
  c.send( tok.verify(c.param.token) )
})

//运行在1234端口
app.run(1234)

/**
HTTP 消息头 content-type 指定了数据的类型（数据的格式）。

Client                                        Server
  content-type描述的值                            根据content-type的值决定如何解析Body数据。
  要和提交的Body数据格式一致。

  content-type:
    multipart/form-data;boundary=xxx   ------   文件解析  

    text/*             ----------------------   文本类型

    application/*      ----------------------   要看具体值，application/json也是文本类型

    ......             ----------------------   每种类型如何处理是双方设计好的通信方式

  到Web框架这一层面，则如何处理是开发框架设计好的，但通常都要遵循一个原则：
        允许开发者做自己的处理。

  在本框架范围内：
      multipart类型  c.body是object类型，文件信息解析到c.files。
      application/x-www-form-urlencoded 传统的表单类型，c.body是object类型，用于获取提交的表单数据。
      text/*  c.body 是文本类型，c.body = c.rawBody.toString('utf8')。
      其他类型： c.body 是buffer类型，就是对c.rawBody的引用。

 */
